/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.ucue.ptc.gco.ngc;

import edu.ucue.ptc.gco.dao.LoteDAOLocal;
import edu.ucue.ptc.gco.dao.ProductoDAOLocal;
import edu.ucue.ptc.gco.mdl.Categoria;
import edu.ucue.ptc.gco.mdl.Lote;
import edu.ucue.ptc.gco.mdl.Producto;
import edu.ucue.ptc.gco.util.AtributoInvalidoException;
import edu.ucue.ptc.gco.util.ElementoYaExisteException;
import edu.ucue.ptc.gco.util.InsuficienteStockException;
import edu.ucue.ptc.gco.util.ValidarAtributoUtil;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateful;
import javax.inject.Inject;
import javax.inject.Named;

/**
 *
 * @author Marcelo
 */
@Stateful
@Named(value = "productoManager")
public class ProductoManager implements ProductoManagerLocal {

    @Inject
    private ProductoDAOLocal productoDao;
    @Inject
    private LoteDAOLocal loteDao;
    @EJB
    private CategoriaManagerLocal ejbCategoria;
    //@EJB
    //private LoteManagerLocal ejbLote;
    @EJB
    private UsuarioManagerLocal ejbRefUsuario;

    @Override
    public void crear(Producto producto, String usuario, String password) throws AtributoInvalidoException, ElementoYaExisteException, Exception {
        ejbRefUsuario.existeUsuario(usuario, password);
        ValidarAtributoUtil.validarObjetoNulo("producto", producto);
        ValidarAtributoUtil.validarObjetoNulo("categoria", producto.getCategoria());


        ValidarAtributoUtil.validarStringNuloVacio("nombreProducto", producto.getNombreProducto());

        //try {
        //productoDao.crear(producto);
        /*} catch (Throwable e) {
         System.out.println("e");
         e.printStackTrace();
         }
         if (true) {
         return;
         }*/
        try {
            Producto p = this.obtenerPorId(producto.getIdProducto(), usuario, password);
            Categoria c = ejbCategoria.obtenerPorId(producto.getCategoria().getIdCategoria(), usuario, password);
            List<Lote> lotes = producto.getLotes();

            if (p != null) {
                throw new ElementoYaExisteException("Producto con id " + p.getIdProducto() + " ya existe.");
            } else if (c == null) {
                throw new AtributoInvalidoException("categoria", producto.getCategoria().getIdCategoria(), "El producto debe tener una categoria que exista");
            }
            List<Lote> lotesAux = producto.getLotes();
            if (lotes != null && lotes.size() > 0) {
                producto.setLotes(new ArrayList<Lote>());
            }

            productoDao.crear(producto);

            producto.setLotes(lotesAux);
            if (lotes != null && lotes.size() > 0) {

                for (Lote lote : lotes) {
                    if (lote != null) {
                        lote.setProducto(producto);
                        if (lote.getIdLote() == -1) {
                            lote.setIdLote(0);
                        }
                        Lote loteExistente = loteDao.obtenerPorId(lote.getIdLote());
                        if (loteExistente == null) {
                            loteDao.crear(lote);
                            //throw new AtributoInvalidoException("lotes", lote.getIdLote(), "El lote con id " + lote.getIdLote() + " no existe");
                        }
                    }
                }
            }
        } catch (Exception ex) {


            if (ex instanceof ElementoYaExisteException) {
                throw (ElementoYaExisteException) ex;
            } else if (ex instanceof AtributoInvalidoException) {
                throw (AtributoInvalidoException) ex;
            } else {
                ex.printStackTrace();
                throw new Exception("Error desconocido: " + ex.getLocalizedMessage() + " - " + ex.getCause());
            }

        }
    }

    @Override
    public void actualizar(Producto producto, String usuario, String password) throws AtributoInvalidoException, Exception {
        ejbRefUsuario.existeUsuario(usuario, password);
        ValidarAtributoUtil.validarObjetoNulo("categoria", producto.getCategoria());

        ValidarAtributoUtil.validarStringNuloVacio("nombreProducto", producto.getNombreProducto());

        try {
            Producto p = this.obtenerPorId(producto.getIdProducto(), usuario, password);
            Categoria c = ejbCategoria.obtenerPorId(producto.getCategoria().getIdCategoria(), usuario, password);
            List<Lote> lotes = producto.getLotes();

            if (p == null) {
                throw new AtributoInvalidoException("producto", producto.getIdProducto(), "El producto con id " + producto.getIdProducto() + " debe existir");
            } else if (c == null) {
                throw new AtributoInvalidoException("categoria", producto.getCategoria().getIdCategoria(), "El producto debe tener una categoria que exista");
            } else if (lotes != null && lotes.size() > 0) {
                for (Lote lote : lotes) {
                    Lote loteExistente = loteDao.obtenerPorId(lote.getIdLote());
                    if (loteExistente == null) {
                        throw new AtributoInvalidoException("lotes", lote.getIdLote(), "El lote con id " + lote.getIdLote() + " no existe");
                    }
                }
            }
            productoDao.actualizar(producto);
        } catch (Exception ex) {


            if (ex instanceof AtributoInvalidoException) {
                throw (AtributoInvalidoException) ex;
            } else {
                ex.printStackTrace();
                throw new Exception("Error desconocido: " + ex.getLocalizedMessage() + " - " + ex.getCause());
            }

        }

    }

    @Override
    public void eliminar(Producto producto, String usuario, String password) throws Exception {
        ejbRefUsuario.existeUsuario(usuario, password);
        try {

            ValidarAtributoUtil.validarObjetoNulo("producto", producto);

            Producto p = this.obtenerPorId(producto.getIdProducto(), usuario, password);

            if (p == null) {
                throw new AtributoInvalidoException("producto", producto.getIdProducto(), "El producto con id " + producto.getIdProducto() + " debe existir");
            } else {
                productoDao.eliminar(producto);
            }
        } catch (Exception ex) {

            if (ex instanceof AtributoInvalidoException) {
                throw (AtributoInvalidoException) ex;
            } else {
                ex.printStackTrace();
                throw new Exception("Error desconocido: " + ex.getLocalizedMessage() + " - " + ex.getCause());
            }

        }

    }

    @Override
    public void eliminarPorId(int id, String usuario, String password) throws Exception {

        ejbRefUsuario.existeUsuario(usuario, password);
        try {
            Producto p = this.obtenerPorId(id, usuario, password);

            if (p == null) {
                throw new AtributoInvalidoException("producto", id, "El producto con id " + id + " debe existir");
            } else {
                //try {
                productoDao.eliminarPorId(id);
                //} catch (Throwable e) {
                //    System.out.println("err");
                //    e.printStackTrace();
                //}
            }
        } catch (Exception ex) {

            if (ex instanceof AtributoInvalidoException) {
                throw (AtributoInvalidoException) ex;
            } else {
                ex.printStackTrace();
                throw new Exception("Error desconocido: " + ex.getLocalizedMessage() + " - " + ex.getCause());
            }

        }
    }

    @Override
    public List<Producto> listarTodos(String usuario, String password) throws Exception {
        ejbRefUsuario.existeUsuario(usuario, password);
        try {
            return productoDao.listarTodos();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new Exception("Error desconocido en listarTodos: " + ex.getLocalizedMessage() + " - " + ex.getCause());
        }
    }

    @Override
    public Producto obtenerPorId(int idProducto, String usuario, String password) throws Exception {
        ejbRefUsuario.existeUsuario(usuario, password);
        try {
            return productoDao.obtenerPorId(idProducto);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new Exception("Error desconocido en obtenerPorId: " + ex.getLocalizedMessage() + " - " + ex.getCause());
        }
    }

    @Override
    public Long obtenerTotalStock(int idProducto, String usuario, String password) throws AtributoInvalidoException, Exception {
        ejbRefUsuario.existeUsuario(usuario, password);
        try {
            Producto p = this.obtenerPorId(idProducto, usuario, password);
            if (p == null) {
                throw new AtributoInvalidoException("producto", idProducto, "El producto con id " + idProducto + " debe existir");
            }

            return loteDao.totalStock(idProducto, Calendar.getInstance().getTime());
        } catch (Exception ex) {
            if (ex instanceof AtributoInvalidoException) {
                throw (AtributoInvalidoException) ex;
            } else if (ex instanceof InsuficienteStockException) {
                throw (InsuficienteStockException) ex;
            } else {
                ex.printStackTrace();
                throw new Exception("Error desconocido: " + ex.getLocalizedMessage() + " - " + ex.getCause());
            }

        }

    }

    @Override
    public String testProducto(String nombreProducto, String usuario, String password) throws AtributoInvalidoException {
        try {
            Categoria categoria = ejbCategoria.obtenerPorId(1, usuario, password);
            if (categoria == null) {
                categoria = new Categoria();
                categoria.setNombre("carnes");
                ejbCategoria.crear(categoria, usuario, password);
            }
            System.out.println("u: " + usuario);
            Producto p = new Producto();
            p.setNombreProducto("nuevo prod");
            p.setDescripcion("nueva desc");
            p.setCategoria(categoria);
            productoDao.crear(p);

             
            return "ok";
        } catch (AtributoInvalidoException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "err";
    }

    @Override
    public void disminuirStock(int idProducto, int cantidad, String usuario, String password) throws AtributoInvalidoException, InsuficienteStockException, Exception {
        ejbRefUsuario.existeUsuario(usuario, password);
        if (cantidad <= 0) {
            throw new AtributoInvalidoException("cantidad", cantidad, "La cantidad debe ser mayor a cero");
        }
        try {
            Producto p = this.obtenerPorId(idProducto, usuario, password);
            if (p == null) {
                throw new AtributoInvalidoException("producto", idProducto, "El producto con id " + idProducto + " debe existir");
            }

            Long stockDisponible = this.obtenerTotalStock(idProducto, usuario, password);
            if (stockDisponible < cantidad) {
                throw new InsuficienteStockException("No hay la cantidad suficiente (" + stockDisponible + ") del producto con id " + idProducto + " para disminuir el stock");
            }

            HashMap<String, Object> parametros = new HashMap<String, Object>();
            parametros.put("fechaActual", Calendar.getInstance().getTime());
            loteDao.lotes(Calendar.getInstance().getTime());
            List<Lote> lotesR = loteDao.lotes(Calendar.getInstance().getTime());

            int cantidadParaQuitar = cantidad;
            for (Lote lote : lotesR) {
                if (lote.getCantidadActual() >= cantidadParaQuitar && cantidadParaQuitar > 0) {
                    lote.setCantidadActual(lote.getCantidadActual() - cantidadParaQuitar);

                    cantidadParaQuitar = 0;

                    loteDao.actualizar(lote);
                } else if (cantidadParaQuitar > 0) {
                    cantidadParaQuitar -= lote.getCantidadActual();
                    lote.setCantidadActual(0);

                    loteDao.actualizar(lote);
                }

                if (cantidadParaQuitar <= 0) {
                    break;
                }
            }

        } catch (Exception ex) {
            if (ex instanceof AtributoInvalidoException) {
                throw (AtributoInvalidoException) ex;
            } else if (ex instanceof InsuficienteStockException) {
                throw (InsuficienteStockException) ex;
            } else {
                ex.printStackTrace();
                throw new Exception("Error desconocido: " + ex.getLocalizedMessage() + " - " + ex.getCause());
            }

        }
    }

   
    @Override
    public List<Producto> listarNombre(String nombre){
        //ejbRefUsuario.existeUsuario(usuario, password);
        List<Producto> obtenerPorNombre = productoDao.obtenerPorNombre(nombre);
       return obtenerPorNombre;
        
    }
        
    @Override
    public List<Lote> lotesProducto(int cantidadRequerida, int idProducto, String usuario, String password) throws AtributoInvalidoException, InsuficienteStockException, Exception {
        ejbRefUsuario.existeUsuario(usuario, password);
        if (cantidadRequerida <= 0) {
            throw new AtributoInvalidoException("cantidad", cantidadRequerida, "La cantidad debe ser mayor a cero");
        }
        
        List<Lote> lotesDeProducto = new ArrayList<Lote>();

        try {
            Producto p = this.obtenerPorId(idProducto, usuario, password);
            if (p == null) {
                throw new AtributoInvalidoException("producto", idProducto, "El producto con id " + idProducto + " debe existir");
            }

            Long stockDisponible = this.obtenerTotalStock(idProducto, usuario, password);
            if (stockDisponible < cantidadRequerida) {
                throw new InsuficienteStockException("No hay la cantidad suficiente (" + stockDisponible + ") del producto con id " + idProducto + " para disminuir el stock");
            }

            HashMap<String, Object> parametros = new HashMap<String, Object>();
            parametros.put("fechaActual", Calendar.getInstance().getTime());
            loteDao.lotes(Calendar.getInstance().getTime());
            List<Lote> lotesR = loteDao.lotes(Calendar.getInstance().getTime());

            int cantidadParaQuitar = cantidadRequerida;
            for (Lote lote : lotesR) {
                if (lote.getCantidadActual() >= cantidadParaQuitar && cantidadParaQuitar > 0) {
                    
                    lote.setCantidadTomada( cantidadParaQuitar );
                    cantidadParaQuitar = 0;
                    lotesDeProducto.add(lote);
                } else if (cantidadParaQuitar > 0) {
                    cantidadParaQuitar -= lote.getCantidadActual();
                    
                    lote.setCantidadTomada( lote.getCantidadActual() );
                    lotesDeProducto.add(lote);
                }

                if (cantidadParaQuitar <= 0) {
                    break;
                }
            }

        } catch (Exception ex) {
            if (ex instanceof AtributoInvalidoException) {
                throw (AtributoInvalidoException) ex;
            } else if (ex instanceof InsuficienteStockException) {
                throw (InsuficienteStockException) ex;
            } else {
                ex.printStackTrace();
                throw new Exception("Error desconocido: " + ex.getLocalizedMessage() + " - " + ex.getCause());
            }

        }

        return lotesDeProducto;
    }
    
    public void disminuirStock2(int idProducto, int cantidad,int idLote, String usuario, String password) throws AtributoInvalidoException, InsuficienteStockException, Exception {
        ejbRefUsuario.existeUsuario(usuario, password);
        if (cantidad <= 0) {
            throw new AtributoInvalidoException("cantidad", cantidad, "La cantidad debe ser mayor a cero");
        }
        try {
            Producto p = this.obtenerPorId(idProducto, usuario, password);
            if (p == null) {
                throw new AtributoInvalidoException("producto", idProducto, "El producto con id " + idProducto + " debe existir");
            }

            Long stockDisponible = this.obtenerTotalStock(idProducto, usuario, password);
            if (stockDisponible < cantidad) {
                throw new InsuficienteStockException("No hay la cantidad suficiente (" + stockDisponible + ") del producto con id " + idProducto + " para disminuir el stock");
            }

            HashMap<String, Object> parametros = new HashMap<String, Object>();
            parametros.put("fechaActual", Calendar.getInstance().getTime());
            loteDao.lotes(Calendar.getInstance().getTime());
            List<Lote> lotesR = loteDao.lotes(Calendar.getInstance().getTime());
            //loteDao.
            int cantidadParaQuitar = cantidad;
            //for (Lote lote : lotesR) 
            for (int i=0; i<lotesR.size(); i++) 
            {
                //if(lote.getProducto().g ==idLote)
                if(lotesR.get(i).getIdLote()==idLote)
                {
                    if (lotesR.get(i).getCantidadActual() >= cantidad && cantidadParaQuitar > 0) {
                        lotesR.get(i).setCantidadActual(lotesR.get(i).getCantidadActual()-cantidad);
                        loteDao.actualizar(lotesR.get(i));
                    }
                }
            }
                    /*
            int cantidadParaQuitar = cantidad;
            for (Lote lote : lotesR) {
                if (lote.getCantidadActual() >= cantidadParaQuitar && cantidadParaQuitar > 0) {
                    lote.setCantidadActual(lote.getCantidadActual() - cantidadParaQuitar);

                    cantidadParaQuitar = 0;

                    loteDao.actualizar(lote);
                } else if (cantidadParaQuitar > 0) {
                    cantidadParaQuitar -= lote.getCantidadActual();
                    lote.setCantidadActual(0);

                    loteDao.actualizar(lote);
                }

                if (cantidadParaQuitar <= 0) {
                    break;
                }
            }*/

        } catch (Exception ex) {
            if (ex instanceof AtributoInvalidoException) {
                throw (AtributoInvalidoException) ex;
            } else if (ex instanceof InsuficienteStockException) {
                throw (InsuficienteStockException) ex;
            } else {
                ex.printStackTrace();
                throw new Exception("Error desconocido: " + ex.getLocalizedMessage() + " - " + ex.getCause());
            }

        }
    }
}
